package com.filldream.fastboot.core.manager;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.filldream.fastboot.base.mapper.StockDayInfoMapper;
import com.filldream.fastboot.base.mapper.StockIndexFuturesMapper;
import com.filldream.fastboot.base.mapper.StockMapper;
import com.filldream.fastboot.common.constant.enums.StockMarketUtil;
import com.filldream.fastboot.common.entity.R;
import com.filldream.fastboot.common.entity.db.StockBaseInfo;
import com.filldream.fastboot.common.entity.db.StockDayInfo;
import com.filldream.fastboot.common.okutil.stock.cf.kline.KLineItemDTO;
import com.filldream.fastboot.common.okutil.stock.cffex.GetStockFuturesSTO;
import com.filldream.fastboot.common.stockUtils.cffex.CffexUtil;
import com.filldream.fastboot.common.stockUtils.cffex.entity.*;
import com.filldream.fastboot.common.stockUtils.qt.entity.StockInfo;
import com.filldream.fastboot.common.stockUtils.qt.StockUtil;
import com.filldream.fastboot.common.util.JsonUtil;
import com.filldream.fastboot.common.util.TransferUtil;
import com.filldream.fastboot.core.thread.ThreadPoolUtil;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
@AllArgsConstructor
public class StockManager {

    private final StockMapper stockMapper;

    private final StockDayInfoMapper stockDayInfoMapper;

    private final StockIndexFuturesMapper stockIndexFuturesMapper;

    /**
     * 根据股票模糊词获取股票信息列表
     *
     * @param stockKey
     * @return
     */
    public R<List<StockBaseInfo>> getList(String stockKey) {
        List<String> thsMarketIdList = StockMarketUtil.getThsMarketIdList();
        R<List<StockBaseInfo>> result = StockUtil.getStockCodeByName(stockKey);
        List<StockBaseInfo> list = result.getData();
        if (ObjectUtils.isNotEmpty(list)) {
            List<StockBaseInfo> realList = list.stream().filter(t ->
                    thsMarketIdList.contains(t.getMarketId())
            ).collect(Collectors.toList());
            result.setData(realList);
            ThreadPoolUtil.R.getExecutor().execute(() -> {
                autoAppendStock(realList);
            });
        }
        return result;
    }

    /**
     * 自动添加股票信息到数据库
     *
     * @param list
     * @return
     */
    public Boolean autoAppendStock(List<StockBaseInfo> list) {
        if (ObjectUtils.isNotEmpty(list)) {
            for (StockBaseInfo stockBaseInfo : list) {
                Integer count = stockMapper.countByStockCode(stockBaseInfo.getStockCode());
                if (count <= 0) {
                    stockBaseInfo.setStockId(null);
                    stockMapper.insert(stockBaseInfo);
                }
            }
        }
        return true;
    }

    /**
     * 自动保存股票日K线相关数据
     */
    public void autoSaveStockDayInfo() {
        if (StockUtil.isInTime(HolidayManager.nowIsHoliday())) {
            String codes = stockDayInfoMapper.getWaitSaveList();
            if (StringUtils.isNotBlank(codes)) {
                List<StockInfo> list = StockUtil.getByCodes(codes);
                for (StockInfo item : list) {
                    StockDayInfo stockDayInfo = TransferUtil.changeToObj(item, StockDayInfo.class);
                    stockDayInfo.setCreateDate(new Date());
                    stockDayInfoMapper.insert(stockDayInfo);
                }
            }
        }
    }

    public Object getStockIndexFutures(GetStockFuturesSTO sto) {
        String date = sto.getDate();
        String productId = sto.getProductId();
        Integer searchType = sto.getSearchType();
        String partyId = sto.getPartyId();
        if( searchType == 0 ){
            return getFuturesPartyList();
        }else if( searchType == 1 ) {
            return getStockIndexFuturesByDay(date, productId);
        }else if( searchType == 2 ){
            return getStockIndexFuturesByDayGroup(date, productId,partyId);
        }else if( searchType == 3 ){
            return StringUtils.isBlank(partyId) ? getStockIndexFuturesByDailyStatistics(date, productId) : getStockIndexFuturesByDailyStatisticsFilter(date, productId, partyId);
        }else if( searchType == 4 ){
            return StringUtils.isBlank(partyId) ? getStockIndexFuturesByDailyStatisticsParty(date) : getStockIndexFuturesByDailyStatisticsPartyFilter(date,partyId);
        }
        return R.autoSuccess(null);
    }

    public List<StockIndexFutureDailyStatistics> getStockIndexFuturesByDailyStatisticsParty(String date){
        List<StockIndexFutureDailyStatistics> result = new ArrayList<>();
        //查询所有的股指期货
        List<String> productIdList = Arrays.stream(StockIndexFutureProductTypeEnum.values()).map(item -> item.getDataTypeId()).collect(Collectors.toList());
        List<StockIndexFuture> list = new ArrayList<>();
        for (String s : productIdList) {
            list.addAll(getStockIndexFuturesByDay(date, s));
        }
        //按照机构分组
        Map<String, List<StockIndexFuture>> partyMap = list.stream().collect(Collectors.groupingBy(StockIndexFuture::getPartyid));
        for (Map.Entry<String, List<StockIndexFuture>> partyMapItem : partyMap.entrySet()) {
            String partyId = partyMapItem.getKey();
            List<StockIndexFuture> partyItemList = partyMapItem.getValue();
            StockIndexFutureDailyStatistics realItem = new StockIndexFutureDailyStatistics();
            realItem.setShortname( partyItemList.get(0).getShortname() );
            realItem.setPartyId(partyId );

            Integer buyVolume = null;
            Integer sellVolume = null;
            for (StockIndexFuture item : partyItemList) {
                if( item.getDatatypeid().equals(1) ){
                    buyVolume = buyVolume == null ? 0 : buyVolume;
                    buyVolume += item.getVarvolume();
                }else if(item.getDatatypeid().equals(2)){
                    sellVolume = sellVolume == null ? 0 : sellVolume;
                    sellVolume += item.getVarvolume();
                }
            }
            realItem.setBuyVolume(buyVolume);
            realItem.setSellVolume(sellVolume);
            if( sellVolume != null && buyVolume != null ){
                realItem.setOnlySellVolume(sellVolume - buyVolume);
            }
            realItem.setKLineData( list.get(0).getKLineData() );
            result.add(realItem);
        }
        //默认按净空单降序，如果为null则排最后
        result.sort(Comparator.comparing(
                StockIndexFutureDailyStatistics::getOnlySellVolume,
                Comparator.nullsLast(Comparator.reverseOrder())
        ));
        return result;
    }

    public List<StockIndexFutureDailyStatistics> getStockIndexFuturesByDailyStatisticsPartyFilter(String date,String partyId){
        List<StockIndexFutureDailyStatistics> result = new ArrayList<>();
        //查询所有的股指期货
        List<String> productIdList = Arrays.stream(StockIndexFutureProductTypeEnum.values()).map(item -> item.getDataTypeId()).collect(Collectors.toList());
        List<StockIndexFuture> list = new ArrayList<>();
        for (String s : productIdList) {
            list.addAll(getStockIndexFuturesByDay(date, s));
        }
        //过滤机构
        list = list.stream().filter(t -> t.getPartyid().equals(partyId)).collect(Collectors.toList());
        //按照机构股指期货类型
        Map<String, List<StockIndexFuture>> productMap = list.stream().collect(Collectors.groupingBy(StockIndexFuture::getProductid));
        for (Map.Entry<String, List<StockIndexFuture>> productMapItem : productMap.entrySet()) {
            String productId = productMapItem.getKey();
            List<StockIndexFuture> partyItemList = productMapItem.getValue();
            StockIndexFutureDailyStatistics realItem = new StockIndexFutureDailyStatistics();
            realItem.setShortname( partyItemList.get(0).getShortname() + "-" + Objects.requireNonNull(StockIndexFutureProductTypeEnum.findById(productId)).getRemark()  );
            realItem.setPartyId(productId );
            Integer buyVolume = null;
            Integer sellVolume = null;
            for (StockIndexFuture item : partyItemList) {
                if( item.getDatatypeid().equals(1) ){
                    buyVolume = buyVolume == null ? 0 : buyVolume;
                    buyVolume += item.getVarvolume();
                }else if(item.getDatatypeid().equals(2)){
                    sellVolume = sellVolume == null ? 0 : sellVolume;
                    sellVolume += item.getVarvolume();
                }
            }
            realItem.setBuyVolume(buyVolume);
            realItem.setSellVolume(sellVolume);
            if( sellVolume != null && buyVolume != null ){
                realItem.setOnlySellVolume(sellVolume - buyVolume);
            }
            realItem.setKLineData( list.get(0).getKLineData() );
            result.add(realItem);
        }
        //默认按净空单降序，如果为null则排最后
        result.sort(Comparator.comparing(
                StockIndexFutureDailyStatistics::getOnlySellVolume,
                Comparator.nullsLast(Comparator.reverseOrder())
        ));
        return result;
    }

    public List<StockIndexFutureDailyStatistics> getStockIndexFuturesByDailyStatistics(String date, String productId){
        List<StockIndexFutureDailyStatistics> result = new ArrayList<>();
        List<StockIndexFuture> list = getStockIndexFuturesByDay(date, productId);
        //按照机构分组
        Map<String, List<StockIndexFuture>> partyMap = list.stream().collect(Collectors.groupingBy(StockIndexFuture::getPartyid));
        for (Map.Entry<String, List<StockIndexFuture>> partyMapItem : partyMap.entrySet()) {
            String partyid = partyMapItem.getKey();
            List<StockIndexFuture> partyItemList = partyMapItem.getValue();
            StockIndexFutureDailyStatistics realItem = new StockIndexFutureDailyStatistics();
            realItem.setShortname( partyItemList.get(0).getShortname() );
            realItem.setPartyId(partyid );

            Integer buyVolume = null;
            Integer sellVolume = null;
            for (StockIndexFuture item : partyItemList) {
                if( item.getDatatypeid().equals(1) ){
                    buyVolume = buyVolume == null ? 0 : buyVolume;
                    buyVolume += item.getVarvolume();
                }else if(item.getDatatypeid().equals(2)){
                    sellVolume = sellVolume == null ? 0 : sellVolume;
                    sellVolume += item.getVarvolume();
                }
            }
            realItem.setBuyVolume(buyVolume);
            realItem.setSellVolume(sellVolume);
            if( sellVolume != null && buyVolume != null ){
                realItem.setOnlySellVolume(sellVolume - buyVolume);
            }
            realItem.setKLineData( list.get(0).getKLineData() );
            result.add(realItem);
        }
        //默认按净空单降序，如果为null则排最后
        result.sort(Comparator.comparing(
            StockIndexFutureDailyStatistics::getOnlySellVolume,
            Comparator.nullsLast(Comparator.reverseOrder())
        ));
        return result;
    }

    public List<StockIndexFutureDailyStatistics> getStockIndexFuturesByDailyStatisticsFilter(String date, String productId,String partyId){
        List<StockIndexFutureDailyStatistics> result = new ArrayList<>();
        List<StockIndexFuture> list = getStockIndexFuturesByDay(date, productId);
        //按照机构过滤
        Stream<StockIndexFuture> partyDateList = list.stream().filter(t -> t.getPartyid().equals(partyId));
       //按照合约分组
        Map<String, List<StockIndexFuture>> instrumentMap = partyDateList.collect(Collectors.groupingBy(StockIndexFuture::getInstrumentid));
        for (Map.Entry<String, List<StockIndexFuture>> instrumentMapItem : instrumentMap.entrySet()) {
            String instrumentId = instrumentMapItem.getKey();
            List<StockIndexFuture> instrumentIdItemList = instrumentMapItem.getValue();
            StockIndexFutureDailyStatistics realItem = new StockIndexFutureDailyStatistics();
            realItem.setShortname( instrumentIdItemList.get(0).getShortname() + "-"+ instrumentId );
            realItem.setPartyId(instrumentId);
            Integer buyVolume = null;
            Integer sellVolume = null;
            for (StockIndexFuture item : instrumentIdItemList) {
                if( item.getDatatypeid().equals(1) ){
                    buyVolume = buyVolume == null ? 0 : buyVolume;
                    buyVolume += item.getVarvolume();
                }else if(item.getDatatypeid().equals(2)){
                    sellVolume = sellVolume == null ? 0 : sellVolume;
                    sellVolume += item.getVarvolume();
                }
            }
            realItem.setBuyVolume(buyVolume);
            realItem.setSellVolume(sellVolume);
            if( sellVolume != null && buyVolume != null ){
                realItem.setOnlySellVolume(sellVolume - buyVolume);
            }
            realItem.setKLineData( list.get(0).getKLineData() );
            result.add(realItem);
        }
        //默认按净空单降序，如果为null则排最后
        result.sort(Comparator.comparing(
                StockIndexFutureDailyStatistics::getOnlySellVolume,
                Comparator.nullsLast(Comparator.reverseOrder())
        ));
        return result;
    }

    public List<StockIndexFutureGroup> getStockIndexFuturesByDayGroup(String date, String productId,String partyId){
        List<StockIndexFutureGroup> result = new ArrayList<>();
        List<StockIndexFuture> list = getStockIndexFuturesByDay(date, productId);
        //按照合约分组
        Map<String, List<StockIndexFuture>> instrumentMap = list.stream().collect(Collectors.groupingBy(StockIndexFuture::getInstrumentid));
        //遍历合约
        for (Map.Entry<String, List<StockIndexFuture>> instrumentItem : instrumentMap.entrySet()) {
            String instrumentId = instrumentItem.getKey();
            List<StockIndexFuture> instrumentItemList = instrumentItem.getValue();
            StockIndexFutureGroup instrumentChild = new StockIndexFutureGroup();
            instrumentChild.setInstrumentid(instrumentId);
            instrumentChild.setTradingday( date.replaceAll(  "-", "") );
            List<StockIndexFutureGroupItem> instrumentChildList = new ArrayList<>();
            //每个合约按照数据类型分组
            Map<Integer, List<StockIndexFuture>> datatypeMap =  instrumentItemList.stream().collect(Collectors.groupingBy(StockIndexFuture::getDatatypeid));
            //按数据类型0，1，2排序
            datatypeMap = new TreeMap<>(datatypeMap);
            for (Map.Entry<Integer, List<StockIndexFuture>> datatypeItem : datatypeMap.entrySet()) {
                Integer dateType = datatypeItem.getKey();
                List<StockIndexFuture> dateTypeItemList = datatypeItem.getValue();
                dateTypeItemList.sort(Comparator.comparingInt(StockIndexFuture::getRank));
                if( dateType.equals(2) ){
                    List<StockIndexFuture> buyList = instrumentChildList.stream().filter(t -> t.getDatatypeid().equals(1)).findFirst().orElse(null).getList();
                    for (StockIndexFuture item : dateTypeItemList) {
                        buyList.stream().filter( t -> t.getPartyid().equals(item.getPartyid()) ).findFirst().ifPresent( t ->{
                            item.setOnlySellNumber( item.getVarvolume() - t.getVarvolume() );
                        });
                    }
                }
                StockIndexFutureGroupItem datatypeChild = new StockIndexFutureGroupItem();
                datatypeChild.setDatatypeid(dateType);
                datatypeChild.setList(dateTypeItemList);
                instrumentChildList.add( datatypeChild );
            }
            instrumentChild.setList( instrumentChildList );
            result.add(instrumentChild);
        }
        result.sort(Comparator.comparing(StockIndexFutureGroup::getInstrumentid));

        //过滤机构
        if( StringUtils.isNotBlank(partyId) ){
            int emptyNumber = 0;
            for (StockIndexFutureGroup item : result) {
                List<StockIndexFutureGroupItem> instrumentList = item.getList();
                for (StockIndexFutureGroupItem dateTypeItem : instrumentList) {
                    boolean isEmpty = false;
                    List<StockIndexFuture> dateItemList = dateTypeItem.getList();
                    List<StockIndexFuture> realList = dateItemList.stream().filter(t -> t.getPartyid().equals(partyId)).collect(Collectors.toList());
                    //没有则自己创建一个
                    if( realList.isEmpty() ){
                        isEmpty = true;
                        StockIndexFuture bi = list.stream().filter(t -> t.getPartyid().equals(partyId)).findFirst().orElse(null);
                        if( bi != null ){
                            StockIndexFuture stockIndexFuture = new StockIndexFuture();
                            stockIndexFuture.setShortname( bi.getShortname() );
                            stockIndexFuture.setVarvolume( null );
                            stockIndexFuture.setVolume( null );
                            stockIndexFuture.setRank( 99 );
                            stockIndexFuture.setPartyid( partyId );
                            realList.add( stockIndexFuture );
                        }
                    }
                    dateTypeItem.setList( realList );
                    emptyNumber = emptyNumber + (isEmpty ? 1 : 0);
                }
            }
            if( emptyNumber >= result.size() * 3 ){
                result = new ArrayList<>();
            }
        }
        return result;
    }


    /**
     * 获取指定日期的股指期货数据
     * @param date  日期
     * @param productId 股指期货类型
     * @return
     */
    public List<StockIndexFuture> getStockIndexFuturesByDay(String date, String productId){
        List<StockIndexFuture> list = stockIndexFuturesMapper.selectList(
                new LambdaQueryWrapper<StockIndexFuture>()
                        .eq(StockIndexFuture::getTradingday, date.replaceAll("-", ""))
                        .eq(StockIndexFuture::getProductid, productId)
        );
        if (ObjectUtils.isEmpty(list)) {
            list = CffexUtil.getIndexFutureWithKLine(date, productId);
            doCache(list);
        }
        long id = DateUtil.currentSeconds();
        for (StockIndexFuture t : list) {
            id = id + 1;
            t.setKLineData(JsonUtil.fromJson(t.getKLineDataJson(),  KLineItemDTO.class));
            t.setKLineDataJson(null);
            t.setId(id);
        }
        return list;
    }

    public List<StockIndexFuture> getFuturesPartyList(){
        return stockIndexFuturesMapper.getFuturesPartyList();
    }

    public void doCache(List<StockIndexFuture> finalList){
        ThreadPoolUtil.R.getExecutor().execute( () ->{
            log.info("----------------------------------------开始同步future数据----------------------------------------");
            for (StockIndexFuture stockIndexFuture : finalList) {
                stockIndexFuture.setKLineDataJson(JsonUtil.toJson(stockIndexFuture.getKLineData()));
                stockIndexFuture.setId(null);
            }
            List<List<StockIndexFuture>> groupList = Lists.partition(finalList, 999);;
            for (int i = 0; i < groupList.size(); i++) {
                List<StockIndexFuture> list = groupList.get(i);
                int insert = stockIndexFuturesMapper.insertBatch22(list);
                if( insert < 1 ){
                    log.info("===================================");
                    log.info("===================================");
                    log.info("===================================");
                    log.info("数据插入失败/数据缓存失败,index:{},size:{}", i, list.size());
                    log.info("===================================");
                    log.info("===================================");
                    log.info("===================================");
                }
            }
            log.info("----------------------------------------结束同步future数据----------------------------------------");
        });
    }

}
